package handler

import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/olivere/elastic/v7"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"google.golang.org/protobuf/types/known/emptypb"
	"mxshop_srvs/goods_srv/global"
	"mxshop_srvs/goods_srv/model"
	"mxshop_srvs/goods_srv/proto"
)

type GoodsServer struct {
	proto.UnimplementedGoodsServer
}

func ModelToResponse(goods model.Goods) *proto.GoodsInfoResponse {

	//zap.S().Info("商品分类名称：", goods.Category.Name, " 商品品牌名称", goods.Brands.Name)
	return &proto.GoodsInfoResponse{
		Id:              goods.ID,
		CategoryId:      goods.CategoryID,
		Name:            goods.Name,
		GoodsSn:         goods.GoodsSn,
		ClickNum:        goods.ClickNum,
		SoldNum:         goods.SoldNum,
		FavNum:          goods.FavNum,
		MarketPrice:     goods.MarketPrice,
		ShopPrice:       goods.ShopPrice,
		GoodsBrief:      goods.GoodsBrief,
		ShipFree:        goods.ShipFree,
		Images:          goods.Images,
		DescImages:      goods.DescImages,
		GoodsFrontImage: goods.GoodsFrontImage,
		IsNew:           goods.IsNew,
		IsHot:           goods.IsHot,
		OnSale:          goods.OnSale,
		AddTime:         goods.BaseModel.CreatedAt.Unix(),
		Category: &proto.CategoryBriefInfoResponse{
			Id:   goods.Category.ID,
			Name: goods.Category.Name,
		},
		Brand: &proto.BrandInfoResponse{
			Id:   goods.Brands.ID,
			Name: goods.Brands.Name,
			Logo: goods.Brands.Logo,
		},
	}

}

// 商品接口
func (g *GoodsServer) GoodsList1(ctx context.Context, req *proto.GoodsFilterRequest) (*proto.GoodsListResponse, error) {

	localDB := global.DB

	//es bool查询(复合查询)
	//关键词搜索、查询新品、查询热门商品、通过价格区间筛选， 通过商品分类筛选
	if req.KeyWords != "" {
		localDB = localDB.Where("name LIKE ?", "%"+req.KeyWords+"%")
	}
	if req.IsNew {
		localDB = localDB.Where("is_new", req.IsNew)
	}
	if req.IsHot {
		localDB = localDB.Where("is_hot", req.IsHot)

	}
	if req.PriceMin > 0 {
		localDB = localDB.Where("shop_price", ">", req.PriceMin)
	}
	if req.PriceMax > 0 {
		localDB = localDB.Where("shop_price", ">", req.PriceMax)
	}
	if req.Brand > 0 {
		localDB = localDB.Where("brands_id", req.Brand)
	}
	//通过category去查询商品
	if req.TopCategory > 0 {
		//判断分类是否存在
		var category model.Category
		if result := global.DB.First(&category, req.TopCategory); result.RowsAffected == 0 {
			return nil, status.Error(codes.NotFound, "分类不存在")
		}
		categorySQL := ""
		if category.Level == 1 {
			categorySQL = fmt.Sprintf("select id from category where id in ("+
				" select id from category where parent_category_id = %d )", req.TopCategory)
		} else if category.Level == 2 {
			categorySQL = fmt.Sprintf(" select id from category where parent_category_id = %d", req.TopCategory)
		} else {
			categorySQL = fmt.Sprintf(" select id from category where id = %d", req.TopCategory)
		}
		localDB = localDB.Where(fmt.Sprintf("category_id in (%s)", categorySQL))

	}
	var total int64
	var goodsList []model.Goods

	localDB.Find(&goodsList).Count(&total)
	localDB.Preload("Category").Preload("Brands").Scopes(Paginate(int(req.Pages), int(req.PagePerNums))).Find(&goodsList)

	var goodsListResponse proto.GoodsListResponse
	for _, goods := range goodsList {

		goodsInfoResponse := ModelToResponse(goods)
		goodsListResponse.Data = append(goodsListResponse.Data, goodsInfoResponse)
	}
	goodsListResponse.Total = int32(int(total))
	return &goodsListResponse, nil
}

// 商品接口
func (g *GoodsServer) GoodsList(ctx context.Context, req *proto.GoodsFilterRequest) (*proto.GoodsListResponse, error) {

	var goodsListResponse proto.GoodsListResponse
	//es bool查询(复合查询)
	query := elastic.NewBoolQuery()
	//关键词搜索、查询新品、查询热门商品、通过价格区间筛选， 通过商品分类筛选
	if req.KeyWords != "" {
		query = query.Must(elastic.NewMultiMatchQuery(req.KeyWords, "name", "goods_brief"))
	}
	if req.IsNew {
		query = query.Filter(elastic.NewTermQuery("is_new", req.IsNew))
	}
	if req.IsHot {
		query = query.Filter(elastic.NewTermQuery("is_hot", req.IsHot))

	}
	if req.PriceMin > 0 {
		query = query.Filter(elastic.NewRangeQuery("shop_price").Gte(req.PriceMin))
	}
	if req.PriceMax > 0 {
		query = query.Filter(elastic.NewRangeQuery("shop_price").Lte(req.PriceMax))
	}
	if req.Brand > 0 {
		query = query.Filter(elastic.NewTermQuery("brands_id", req.Brand))
	}
	//通过category去查询商品
	if req.TopCategory > 0 {
		//判断分类是否存在
		var category model.Category
		if result := global.DB.First(&category, req.TopCategory); result.RowsAffected == 0 {
			return nil, status.Error(codes.NotFound, "分类不存在")
		}
		categorySQL := ""
		if category.Level == 1 {
			categorySQL = fmt.Sprintf("select id from category where id in ("+
				" select id from category where parent_category_id = %d )", req.TopCategory)
		} else if category.Level == 2 {
			categorySQL = fmt.Sprintf(" select id from category where parent_category_id = %d", req.TopCategory)
		} else {
			categorySQL = fmt.Sprintf(" select id from category where id = %d", req.TopCategory)
		}

		type Result struct {
			ID int32
		}
		var results []Result

		if result := global.DB.Model(model.Category{}).Raw(categorySQL).Scan(&results); result != nil {
			return nil, status.Error(codes.Internal, result.Error.Error())
		}
		var categoryIds []interface{}
		for _, result := range results {
			categoryIds = append(categoryIds, result.ID)
		}

		query = query.Filter(elastic.NewTermsQuery("category_id", categoryIds...))
	}

	if req.Pages <= 0 {
		req.Pages = 1
	}
	switch {
	case req.PagePerNums > 100:
		req.PagePerNums = 100
	case req.PagePerNums <= 0:
		req.PagePerNums = 10
	}
	offset := (req.Pages - 1) * req.PagePerNums

	esResult, err := global.EsClient.Search().Index(model.EsGoods{}.GetIndexName()).Query(query).From(int(offset)).Size(int(req.PagePerNums)).Do(context.Background())
	if err != nil {
		return nil, status.Error(codes.Internal, err.Error())
	}

	goodsListResponse.Total = int32(esResult.Hits.TotalHits.Value)

	var goodsIds []int32
	for _, goods := range esResult.Hits.Hits {
		var esGoods model.EsGoods
		err := json.Unmarshal(goods.Source, &esGoods)
		if err != nil {
			return nil, status.Error(codes.Internal, err.Error())
		}
		goodsIds = append(goodsIds, esGoods.ID)
	}

	var goodsList []model.Goods

	global.DB.Preload("Category").Preload("Brands").Find(&goodsList, goodsIds)

	for _, goods := range goodsList {

		goodsInfoResponse := ModelToResponse(goods)
		goodsListResponse.Data = append(goodsListResponse.Data, goodsInfoResponse)
	}
	return &goodsListResponse, nil
}

// //现在用户提交订单有多个商品，你得批量查询商品的信息吧
func (g *GoodsServer) BatchGetGoods(ctx context.Context, req *proto.BatchGoodsIdInfo) (*proto.GoodsListResponse, error) {

	var goodsListResponse proto.GoodsListResponse
	var goodsList []model.Goods
	result := global.DB.Find(&goodsList, req.Id)
	if result.Error != nil {
		return nil, status.Error(codes.Internal, result.Error.Error())
	}
	goodsListResponse.Total = int32(result.RowsAffected)
	for _, good := range goodsList {
		goodsInfoResponse := ModelToResponse(good)
		goodsListResponse.Data = append(goodsListResponse.Data, goodsInfoResponse)
	}
	return &goodsListResponse, nil
}

func (g *GoodsServer) CreateGoods(ctx context.Context, req *proto.CreateGoodsInfo) (*proto.GoodsInfoResponse, error) {

	goods := model.Goods{
		CategoryID:      req.CategoryId,
		BrandsID:        req.BrandId,
		OnSale:          req.OnSale,
		ShipFree:        req.ShipFree,
		IsNew:           req.IsNew,
		IsHot:           req.IsHot,
		Name:            req.Name,
		GoodsSn:         req.GoodsSn,
		MarketPrice:     req.MarketPrice,
		ShopPrice:       req.ShopPrice,
		GoodsBrief:      req.GoodsBrief,
		Images:          req.Images,
		DescImages:      req.DescImages,
		GoodsFrontImage: req.GoodsFrontImage,
	}

	tx := global.DB.Begin()
	result := tx.Save(&goods)
	if result.Error != nil {
		tx.Rollback()
		return nil, status.Error(codes.Internal, result.Error.Error())
	}
	tx.Commit()
	return &proto.GoodsInfoResponse{Id: goods.ID}, nil
}

func (g *GoodsServer) DeleteGoods(ctx context.Context, req *proto.DeleteGoodsInfo) (*emptypb.Empty, error) {

	var goods model.Goods
	tx := global.DB.Begin()
	if result := tx.Find(&goods, req.Id); result.RowsAffected == 0 {
		return nil, status.Error(codes.NotFound, "商品不存在")
	}
	result := tx.Delete(&goods, req.Id)
	if result.Error != nil {
		tx.Rollback()
		return nil, status.Error(codes.Internal, result.Error.Error())
	}
	tx.Commit()
	return &emptypb.Empty{}, nil
}

func (g *GoodsServer) UpdateGoods(ctx context.Context, req *proto.CreateGoodsInfo) (*emptypb.Empty, error) {

	var goods model.Goods
	tx := global.DB.Begin()
	if result := tx.Find(&goods, req.Id); result.RowsAffected == 0 {
		return nil, status.Error(codes.NotFound, "商品不存在")
	}

	goods.OnSale = req.OnSale
	goods.ShipFree = req.ShipFree
	goods.IsNew = req.IsNew
	goods.IsHot = req.IsHot
	goods.Name = req.Name
	goods.GoodsSn = req.GoodsSn
	goods.MarketPrice = req.MarketPrice
	goods.ShopPrice = req.ShopPrice
	goods.Images = req.Images
	goods.GoodsBrief = req.GoodsBrief
	goods.DescImages = req.DescImages
	goods.GoodsFrontImage = req.GoodsFrontImage

	if req.CategoryId > 0 {
		goods.CategoryID = req.CategoryId
	}
	if req.BrandId > 0 {
		goods.BrandsID = req.BrandId
	}
	if result := tx.Save(&goods); result.Error != nil {
		tx.Rollback()
		return nil, status.Error(codes.Internal, result.Error.Error())
	}
	tx.Commit()
	return &emptypb.Empty{}, nil
}

func (g *GoodsServer) GetGoodsDetail(ctx context.Context, req *proto.GoodInfoRequest) (*proto.GoodsInfoResponse, error) {

	var goods model.Goods
	result := global.DB.Find(&goods, req.Id)
	if result.RowsAffected == 0 {
		return nil, status.Error(codes.NotFound, "商品不存在")
	}
	goodsInfoResponse := ModelToResponse(goods)
	return goodsInfoResponse, nil
}
